package com.zhny.aiot.lrh.data.plugin;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.zhny.aiot.lrh.data.plugin.model.EnvDataStoreEntry;
import com.zhny.aiot.lrh.data.plugin.model.response.LoginToken;
import com.zhny.aiot.lrh.data.plugin.model.response.Result;
import com.zhny.aiot.lrh.data.plugin.model.response.ShackEnvConfigResult;
import com.zhny.aiot.lrh.data.plugin.model.response.ShackEnvDataResult;
import com.zhny.aiot.lrh.data.plugin.model.util.MD5Util;
import com.zhny.aiot.plugin.ICenterFacilities;
import com.zhny.aiot.plugin.IDeviceFactory;
import com.zhny.aiot.plugin.core.utils.MessageUtils;
import com.zhny.aiot.plugin.model.DeviceEntity;
import com.zhny.aiot.plugin.model.MessageEntry;
import com.zhny.aiot.plugin.model.MessageType;
import com.zhny.aiot.plugin.model.TaskEntity;
import com.zhny.aiot.plugin.web.WebDevice;
import io.netty.util.internal.StringUtil;
import org.apache.commons.codec.binary.Base64;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.net.URISyntaxException;
import java.util.HashMap;
import java.util.Map;

public class EnvDataDevice extends WebDevice<EnvDataConfig> {
    private static final Logger log = LoggerFactory.getLogger(EnvDataDevice.class);
    private String loginToken = null;
    private Map<String,String> configMap = new HashMap<> ();
    public EnvDataDevice(IDeviceFactory factory, ICenterFacilities centerFacilities, DeviceEntity entity) {
        super (factory, centerFacilities, entity);
    }

    @Override
    protected void onRequestHttp(TaskEntity task, CloseableHttpClient httpClient) {
        log.info ("execute pick eggs api request!");
        onLogin (httpClient);
        if(configMap.size () == 0)
            onEnvConfigResponse (httpClient);
        onEnvDataResponse(httpClient);
    }

    private void onLogin(CloseableHttpClient httpClient) {
        URIBuilder uriBuilder=null;
        EnvDataConfig config=this.getConfig ();
        try {
            uriBuilder=new URIBuilder ("https://hnwlw.loongk.com/mobile/login");
            uriBuilder.addParameter ("username", config.getUsername ());
            uriBuilder.addParameter ("password", MD5Util.getMd5 (config.getPassword ()));

            HttpPost httpPost=new HttpPost (uriBuilder.build ());
            try (CloseableHttpResponse response=httpClient.execute (httpPost)) {
                String body=EntityUtils.toString (response.getEntity ());
                Result<LoginToken> result = deserialize (body, new TypeReference<Result<LoginToken>> () {
                });
                if(result.getData () == null) {
                    log.error ("env data token api result map to error !");
                    return;
                }
                LoginToken token =result.getData ();
                if(token == null){
                    log.error ("{}env data login error ! return token is null !",this.getDeviceEntity ().getName ());
                    return;
                }
                String userId = token.getToken ().get ("userId");
                String tk = token.getToken ().get ("token");
                log.info ("userid:{}",userId);
                log.info ("token:{}",token);
                String code = userId+"_"+tk;

                loginToken = Base64.encodeBase64String(code.getBytes ("utf-8"));
                log.info ("base64 token:{}",loginToken);

            } catch (ClientProtocolException e) {
                throw new RuntimeException (e);
            } catch (ConnectTimeoutException e) {
                throw new RuntimeException ("请求连接超时");
            } catch (IOException e) {
                throw new RuntimeException (e);
            }
        } catch (URISyntaxException e) {
            throw new RuntimeException (e);
        }
    }
//    使用登陆
//    private void onLogin(){
//        EnvDataConfig config = this.getConfig ();
//        String userId = config.getUserId ();
//        String token = config.getToken ();
//        if(StringUtil.isNullOrEmpty (userId))throw new NullPointerException ("invalid config,is null !");
//        if(StringUtil.isNullOrEmpty (token))throw new NullPointerException ("invalid config,is null !");
//        String code = userId+"_"+token;
//        try {
//            this.loginToken = Base64.encodeBase64String(code.getBytes ("utf-8"));
//        } catch (UnsupportedEncodingException e) {
//            throw new RuntimeException (e);
//        }
//    }
    private void onEnvConfigResponse(CloseableHttpClient httpClient){
        log.info ("read env config api response!");
        URIBuilder uriBuilder =null;
        EnvDataConfig config =this.getConfig ();
        try {
            String httpUrl = "https://hnwlw.loongk.com/mobile/loadShackConfig/"+config.getFenceHouseId ()+"";
//            String httpUrl = "https://hnwlw.loongk.com/mobile/loadShackConfig/2c91b76773ba17db0173ec2915320032";
            uriBuilder=new URIBuilder (httpUrl);
            HttpGet httpGet=new HttpGet (uriBuilder.build ());
            httpGet.addHeader ("Authorization",this.loginToken);
            try (CloseableHttpResponse response =httpClient.execute (httpGet) ){
                String body =EntityUtils.toString (response.getEntity ());
                Result<ShackEnvConfigResult> result = deserialize (body, new TypeReference<Result<ShackEnvConfigResult>> () {
                });
                if(result == null){
                    log.error ("{}env config api result map to error !",this.getDeviceEntity ().getName ());return;}
                onSetMap (result.getData ());
            }catch (ClientProtocolException e) {
                throw new RuntimeException (e);
            } catch (ConnectTimeoutException e) {
                throw new RuntimeException("请求连接超时");
            } catch (IOException e) {
                throw new RuntimeException (e);
            }
        } catch (URISyntaxException e) {
            throw new RuntimeException (e);
        }
    }
    public void onSetMap(ShackEnvConfigResult configResult){
        for (Map<String,Object> map: configResult.getSensors ()){
            if(map.containsKey ("id") && map.containsKey ("name"))
                configMap.put ((String) map.get ("id"),(String)map.get ("name"));
        }
        for (Map<String,Object> map: configResult.getControllers ()){
            if(map.containsKey ("id") && map.containsKey ("name"))
                configMap.put ((String)map.get ("id"),(String)map.get ("name"));
        }
    }
    private void onEnvDataResponse(CloseableHttpClient httpClient) {
        log.info ("read env data api response!");
        URIBuilder uriBuilder =null;
        EnvDataConfig config =this.getConfig ();
        try {
//            String httpUrl = "https://hnwlw.loongk.com/mobile/loadShackDatas/2c91b76773ba17db0173ec2915320032";
            String httpUrl = "https://hnwlw.loongk.com/mobile/loadShackDatas/"+config.getFenceHouseId ()+"";
            uriBuilder=new URIBuilder (httpUrl);
            HttpGet httpGet=new HttpGet (uriBuilder.build ());
            httpGet.addHeader ("Authorization",this.loginToken);
            try (CloseableHttpResponse response =httpClient.execute (httpGet) ){
                String body =EntityUtils.toString (response.getEntity ());
                Result<ShackEnvDataResult> result = deserialize (body, new TypeReference<Result<ShackEnvDataResult>> () {
                });
                if(result != null){
                    if(result.getData ().getControllerDatas ().size () == 0)
                        return;
                    if(result.getData ().getSensorDatas ().size () == 0)
                        return;
                    onResponse(result.getData ());
                }else {
                    log.error ("{}env data response is null !",this.getDeviceEntity ().getName ());
                }

            } catch (ClientProtocolException e) {
                throw new RuntimeException (e);
            } catch (ConnectTimeoutException e) {
                throw new RuntimeException("请求连接超时");
            } catch (IOException e) {
                throw new RuntimeException (e);
            }
        } catch (URISyntaxException e) {
            throw new RuntimeException (e);
        }
    }

    public void onResponse(ShackEnvDataResult result) {
        MessageEntry messageEntry = MessageUtils.createMessageEntry(this.getId ());
//        messageEntry.setType (MessageType.RESULT);
//        EnvDataStoreEntry storeEntry = new EnvDataStoreEntry ();
//        setSensorStore(storeEntry,result);
//        setControllerStore (storeEntry,result);
//        messageEntry.setData (storeEntry);
//        save (storeEntry);
//        saveReal (storeEntry);

        String alarmMsg = result.getAlarm ();
        EnvDataStoreEntry storeEntry = new EnvDataStoreEntry ();
        if(!StringUtil.isNullOrEmpty (alarmMsg)){
            log.info ("{}存在报警：{}",this.getDeviceEntity ().getName (),alarmMsg);
            storeEntry.setAlarmMsg (alarmMsg);
            messageEntry.setType (MessageType.ALARM);
            messageEntry.setData (storeEntry);
        }else {
            setSensorStore(storeEntry,result);
            setControllerStore (storeEntry,result);
            messageEntry.setType (MessageType.RESULT);
            messageEntry.setData (storeEntry);
            save (storeEntry);
            saveReal (storeEntry);
        }
        nofity (messageEntry);
    }

    private void setSensorStore(EnvDataStoreEntry entry,ShackEnvDataResult result){
        for (Map<String,Object> map: result.getSensorDatas ()){
            if(configMap.containsKey (map.get ("id"))){
                if(configMap.get (map.get ("id")).contains ("后区温度4"))entry.setTemperature4 ((String)map.get("val"));
                if(configMap.get (map.get ("id")).contains ("后区温度5"))entry.setTemperature5 ((String)map.get("val"));
                if(configMap.get (map.get ("id")).contains ("平均温度"))entry.setTemperature6 ((String)map.get("val"));
                if(configMap.get (map.get ("id")).contains ("前区温度1"))entry.setTemperature2 ((String)map.get("val"));
                if(configMap.get (map.get ("id")).contains ("前区温度2"))entry.setTemperature3 ((String)map.get("val"));
                if(configMap.get (map.get ("id")).contains ("舍外温度"))entry.setTemperature7 ((String)map.get("val"));
                if(configMap.get (map.get ("id")).contains ("中区温度3"))entry.setTemperature1 ((String)map.get("val"));
                if(configMap.get (map.get ("id")).contains ("舍内湿度"))entry.setHumidity ((String)map.get("val"));
                if(configMap.get (map.get ("id")).contains ("CO2"))entry.setCo2 ((String)map.get("val"));
                if(configMap.get (map.get ("id")).contains ("静压"))entry.setStaticPressure ((String)map.get("val"));
                if(configMap.get (map.get ("id")).contains ("用电量"))entry.setElectricity ((String)map.get("val"));
                if(configMap.get (map.get ("id")).contains ("饮水量"))entry.setWater ((String)map.get("val"));
                if(configMap.get (map.get ("id")).contains ("饲料量"))entry.setForage ((String)map.get("val"));
                if(configMap.get (map.get ("id")).contains ("死亡数"))entry.setCullDeath ((String)map.get("val"));
                if(configMap.get (map.get ("id")).contains ("种禽数"))entry.setBreedAmount ((String)map.get("val"));
            }
        }
    }

    private void setControllerStore(EnvDataStoreEntry entry,ShackEnvDataResult result){
        for (Map<String,Object> map: result.getControllerDatas ()){
            if(configMap.containsKey (map.get ("id"))){
                if(configMap.get (map.get ("id")).contains ("变频风机组"))entry.setFan2 (map.get("val").equals ("0")?"关":"开");
                if(configMap.get (map.get ("id")).contains ("侧墙风机组"))entry.setFan1 (map.get("val").equals ("0")?"关":"开");
                if(configMap.get (map.get ("id")).contains ("风机1组"))entry.setFan3 (map.get("val").equals ("0")?"关":"开");
                if(configMap.get (map.get ("id")).contains ("风机2组"))entry.setFan4 (map.get("val").equals ("0")?"关":"开");
                if(configMap.get (map.get ("id")).contains ("风机3组"))entry.setFan5 (map.get("val").equals ("0")?"关":"开");
                if(configMap.get (map.get ("id")).contains ("风机4组"))entry.setFan6 (map.get("val").equals ("0")?"关":"开");
                if(configMap.get (map.get ("id")).contains ("风机5组"))entry.setFan7 (map.get("val").equals ("0")?"关":"开");
                if(configMap.get (map.get ("id")).contains ("卷帘2"))entry.setCurtain1 (map.get("val").equals ("0")?"关":"开");
                if(configMap.get (map.get ("id")).contains ("隧道"))entry.setCurtain3 (map.get("val").equals ("0")?"关":"开");
                if(configMap.get (map.get ("id")).contains ("小窗"))entry.setCurtain2 (map.get("val").equals ("0")?"关":"开");
                if(configMap.get (map.get ("id")).contains ("制冷水帘"))entry.setCoolingpad (map.get("val").equals ("0")?"关":"开");
                if(configMap.get (map.get ("id")).contains ("喂料"))entry.setFeed (map.get("val").equals ("0")?"关":"开");
                if(configMap.get (map.get ("id")).contains ("灯光"))entry.setLight (map.get("val").equals ("0")?"关":"开");
            }
        }
    }
    private <T> T deserialize(String json, Class<T> objectType){
        if(StringUtil.isNullOrEmpty (json))
            return null;
        ObjectMapper mapper=new ObjectMapper ();
        try {
            mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
            T obj=mapper.readValue (json,objectType);
            return obj;
//            return mapper.writeValueAsString(this);
        } catch (IOException e) {
            return null;
        }
    }

    public   <T> T deserialize(String json, TypeReference<T> typeReference){
        if(StringUtil.isNullOrEmpty (json))
            return null;
        ObjectMapper mapper=new ObjectMapper ();
        try {
            mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
            T obj=mapper.readValue (json,typeReference);
            return obj;
//            return mapper.writeValueAsString(this);
        } catch (IOException e) {
            return null;
        }
    }
}
